﻿using Common;
using Log4_Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NoticeWechat.Base
{
    public class CorsMiddleware
    {
        private readonly RequestDelegate _next;
        IConfiguration _configuration;
        ILogger _logger;
        public CorsMiddleware(RequestDelegate next, IConfiguration configuration, ILogHelper logger)
        {
            _next = next;
            _configuration = configuration;
            _logger = logger.GetLogger();
        }

        public async Task Invoke(HttpContext context)
        {
            if (!context.Response.Headers.ContainsKey("Access-Control-Allow-Origin"))
            {
                ////多个跨域才启用
                if (_configuration["Cors:Clients"].IndexOf(",") >= 0)
                {
                    var arr = _configuration["Cors:Clients"].Split(",").ToList();
                    context.Request.Headers.TryGetValue("Origin", out StringValues host);
                    var self = arr.Find(x => x == host.ToString());
                    if (!string.IsNullOrEmpty(self))
                        context.Response.Headers.Add("Access-Control-Allow-Origin", self);
                }
                else
                {
                    context.Response.Headers.Add("Access-Control-Allow-Origin", _configuration["Cors:Clients"]);
                }
                context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
                context.Response.Headers.Add("Access-Control-Allow-Headers", "content-type,origin, x-requested-with, authorization");
                context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

                if (context.Request.Method == "OPTIONS")
                {
                    context.Response.StatusCode = StatusCodes.Status200OK;
                    return;
                }
            }
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex.Message + ex.StackTrace);
                if (IsAjaxRequest(context.Request) ||  IsJsonContextType(context.Request))
                {
                    if (context.Response.HasStarted)
                    {
                        return;
                    }
                    context.Response.StatusCode = StatusCodes.Status500InternalServerError; 
                    context.Response.ContentType = "application/json; charset=utf-8";
                    await context.Response.WriteAsync(new AjaxResult() { Type = ResultType.Failed, Message = ex.Message }.ToJson());
                    return;
                }
                throw;
            }
        }


        /// <summary>
        /// 确定指定的 HTTP 请求是否为 AJAX 请求。
        /// </summary>
        ///
        /// <returns>
        /// 如果指定的 HTTP 请求是 AJAX 请求，则为 true；否则为 false。
        /// </returns>
        /// <param name="request">HTTP 请求。</param>
        /// <exception cref="T:System.ArgumentNullException"><paramref name="request"/> 参数为 null（在 Visual Basic 中为 Nothing）。</exception>
        public bool IsAjaxRequest(HttpRequest request)
        {
            bool? flag = request.Headers?["X-Requested-With"].ToString()?.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase);
            return flag.HasValue && flag.Value;
        }

        /// <summary>
        /// 确定指定的 HTTP 请求的 ContextType 是否为 Json 方式
        /// </summary>
        public bool IsJsonContextType(HttpRequest request)
        {

            bool flag = request.Headers?["Content-Type"].ToString().IndexOf("application/json", StringComparison.OrdinalIgnoreCase) > -1
                || request.Headers?["Content-Type"].ToString().IndexOf("text/json", StringComparison.OrdinalIgnoreCase) > -1;
            if (flag)
            {
                return true;
            }
            flag = request.Headers?["Accept"].ToString().IndexOf("application/json", StringComparison.OrdinalIgnoreCase) > -1
                || request.Headers?["Accept"].ToString().IndexOf("text/json", StringComparison.OrdinalIgnoreCase) > -1;
            return flag;
        }
    }
}
